
#include <BPainter>
#include <BRender>
#include <BViewer>
#include <BCone>
#include <BCube>
#include <BImage>
#include <BReadWrite>
#include <BKeyEvent>

#include <BCube>
#include <BCylinder>
#include <BCapsule>
#include <BScene>
#include <BMatrix>
#include <BBody>
#include <BSoftBody>

#include <BFixedRestraint>
#include <BSliderRestraint>
#include "BasicSampleHandler.h"

BasicSampleHandler::BasicSampleHandler()
{
	_group = new BGroup();
	
	if (BCube* cube = new BCube(1, 2, 3, 20, 20))
	{
		cube->setName("cube");
		cube->setColor(150, 200, 250);

		BBody* body = new BBody();
		body->setMass(5);
		body->insertShape(cube);
		body->setPosition(0, 0, 1);
		//body->setGravity(0, 0, -1);
		body->setRestitution(0.5);
		//body->setContinuous(true);
		_group->insert(body);

		for (int i = 0; i < 5; i++)
		{
			for (int j = 0; j < 5; j++)
			{
				BString name("cube");
				name << '-' << i << '-' << j;
				BBody* body = new BBody(name);
				body->setMass(1);
				body->insertShape(cube);
				body->setPosition(2 * i, 2 * j, 4);
				_group->insert(body);
			}
		}
	}
	
	if (BCone* cone = new BCone(1, 2))
	{
		cone->setName("cone");
		cone->setColor(220, 220, 220);
	
		BBody* body = new BBody();
		body->setMass(1);
		body->insertShape(cone);
		body->setPosition(0, 0, 1);
		_group->insert(body);
	
		for (int i = 0; i < 5; i++)
		{
			for (int j = 0; j < 5; j++)
			{
				BString name("cone");
				name << '-' << i << '-' << j;
				BBody* body = new BBody(name);
				body->setMass(1);
				body->insertShape(cone);
				body->setPosition(2 * i, 2 * j, 4);
				//body->setEuler(bDTR(45), 0, 0);
				_group->insert(body);
			}
		}
	}
	
	{
		_sphere = new BSphere(0.5);
		{
			BImage* image = ReadFile<BImage>("data/picture/jupitermap.jpg");
			image->setBlend(BTexture::Blend_Modulate);

			_sphere->setName("sphere");
			_sphere->setTexture(image);
			//_sphere->setColor(120, 100, 250);
		}

		BBody* body = new BBody();
		body->insertShape(_sphere);
		body->setMass(10);
		body->setRestitution(0.9);
		body->setPosition(0, 0, 1);
		_group->insert(body);

		for (int i = 0; i < 5; i++)
		{
			for (int j = 0; j < 5; j++)
			{
				BString name("sphere");
				name << '-' << i << '-' << j;
				BBody* body = new BBody(name);
				body->insertShape(_sphere);
				body->setPosition((BReal)2 * i, (BReal)2 * j, 6);
				body->setMass(1);
				body->setRestitution(0.9);
				_group->insert(body);
			}
		}
	}
	
	if (BCylinder* cylinder = new BCylinder(1, 5, 24, 6, 6))
	{
		cylinder->setColor(220, 100, 50);
		
		BBody* body = new BBody();
		body->setMass(1);
		body->insertShape(cylinder);
		body->setPosition(0, 0, 1);
		_group->insert(body);
		
		for (int i = 0; i < 6; i++)
		{
			for (int j = 0; j < 6; j++)
			{
				BString name("cylinder");
				name << '-' << i << '-' << j;
				BBody* body = new BBody(name);
				body->setPosition((BReal)2 * i, (BReal)2 * j, 8);
				body->setMass(1);
				body->insertShape(cylinder);
				_group->insert(body);
			}
		}
	}
	
	if (BCapsule* capsule = new BCapsule((BReal)1, (BReal)3))
	{
		capsule->setColor(20, 200, 100);
		for (int i = 0; i < 6; i++)
		{
			for (int j = 0; j < 6; j++)
			{
				BString name("capsule");
				name << '-' << i << '-' << j;
				BBody* body = new BBody(name);
				body->setPosition((BReal)3 * i, (BReal)3 * j, 12);
				body->setMass(1);
				body->insertShape(capsule);
				_group->insert(body);
			}
		}
	}
	
	BBody* capsulesBody = new BBody("capsules");
	{
		capsulesBody->setPosition(-5, -5, 10);
		capsulesBody->setMass(10);
		BReal offset = (BReal)10 / 10;
		BVector origin(-5, -5, 0);
		for (int i = 0; i < 10; i++)
		{
			for (int j = 0; j < 10; j++)
			{
				BString name("sphere");
				name << '-' << i << '-' << j;
				BCapsule* capsule = new BCapsule(0.4, 1, 24, 6, 6);
				capsule->setName(name);
				capsule->setColor(220, 100, 100);
				capsule->setPosition(origin + BVector(offset * i, offset * j, 0));
				capsulesBody->insertShape(capsule);
			}
		}
	}
	_group->insert(capsulesBody);
	
}
BasicSampleHandler::~BasicSampleHandler()
{

}

void BasicSampleHandler::attached(BViewer* viewer)
{
	viewer->scene()->insert(_group);
}
void BasicSampleHandler::detached(BViewer* viewer)
{
	viewer->scene()->remove(_group);
}

void BasicSampleHandler::paint(BPainter& painter)
{
	BViewer* viewer = this->viewer();
}
void BasicSampleHandler::render(BRender& render)
{
	render.setLighting(false);
	render.setDepthTest(false);
	render.setLineSmooth(true);

	for (int i = 0; i < this->scene()->bodyCount(); i++)
	{
		BBody* body = this->scene()->body(i);
		if (body->mass() > REAL_EPSILON)
		{
			const BMatrix& matrix = body->matrix();
			BVector rollingFrictionLinearVelocity = body->query("rolling-friction-linear-velocity");
			BVector rollingFrictionAngularVelocity = body->query("rolling-friction-angular-velocity");
			render.setColor(200, 0, 0);
			render.drawLine(matrix.position(), matrix.position() + rollingFrictionLinearVelocity);
			render.setColor(200, 200, 0);
			render.drawLine(matrix.position(), matrix.position() + rollingFrictionAngularVelocity);
		}
	}

	if (BCamera* camera = this->camera())
	{
		BReal hlen = bMin(camera->lensWidth(), camera->lensHeight()) / 2;
		BVector center = camera->direct() * 0.1 + camera->lensVertex(camera->center());
		BVector vec_up = camera->up() * hlen;
		BVector vec_right = camera->right() * hlen;

		render.setLineWidth(1);
		render.setColor(255, 0, 255);
		render.drawLine(center, center - vec_up);
		render.drawLine(center, center + vec_up);
		render.drawLine(center, center - vec_right);
		render.drawLine(center, center + vec_right);
	}
}

void BasicSampleHandler::keyPressEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_Enter)
	{
		this->fresh();
		keyEvent.accept();
	}
	if (keyEvent.key() == Key_Escape)
	{
		keyEvent.accept();
	}
	if (keyEvent.key() == Key_Space)
	{
		BBody* body = new BBody();
		body->insertShape(_sphere);
		body->setMass(1);
		body->setGravity(0);
		body->setRestitution(0.9);
		body->setPosition(this->camera()->position());
		body->setLinearVelocity(this->camera()->direct() * 200);
		body->setContinuous(true);
		this->scene()->insert(body);
		keyEvent.accept();
	}
}
void BasicSampleHandler::keyReleaseEvent(const BKeyEvent& keyEvent)
{

}
